package com.sophia.common.xmlbean.util;


import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
 * 
 * <p>Title:Health</p>
 * <p>PojoXMLUtil</p>
 * 
 * Alex Apr 12, 2011 8:06:07 PM create
 * @author <a href='wanghao924@126.com'>Alex</a>
 * QQ: 873987060;
 * @version 1.0
 */
public class PojoXMLUtil {

	/**
	 * 
	 * Des:创建一个新的Document对象<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-10
	 */
	public static Document createDocument(){
		try{
			//实例化DOM生成工厂   
	        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();   
	        // 由工厂实例化文档创建器   
	        DocumentBuilder db = dbf.newDocumentBuilder();   
	        // 由文档创建器实例化文档对象   
	        return db.newDocument();
		}catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 
	 * Des:根据XML字符串创建Document对象<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-10
	 */
	public static Document getDocumentByData(String data) {
		return XPathUtil.getDocumentByData(data);
	}
	
	/**
	 * 
	 * Des:根据指定路径创建Document对象<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-10
	 */
	public static Document getDocumentByPath(String path) {
		return XPathUtil.getDocument(path);
	}
	
	/**
	 * 
	 * Des:将Node对象转化成XML字符串<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-10
	 */
	public static String getDomXml(Node node) {   
        String xmlStr = null;   
        try {   
        	// 以 Document Object Model（DOM）树的形式充当转换 Source 树的持有者
            DOMSource source = new DOMSource(node);   	               
  
            // 用来得到XML字符串形式
            // 一个字符流，可以用其回收在字符串缓冲区中的输出来构造字符串。
            StringWriter writerStr = new StringWriter();   
            Result resultStr = new StreamResult(writerStr);   
               
            // 此抽象类的实例能够将源树转换为结果树。
            Transformer transformer = TransformerFactory.newInstance().newTransformer();   
            // 设置编码
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");   
            // 是否缩进
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");   
            // 将 XML Source 转换为 Result
            transformer.transform(source, resultStr);   
  
            // 获取XML字符串
            xmlStr = writerStr.getBuffer().toString();   
        } catch (TransformerException e) {   
            e.printStackTrace();   
        } catch (Exception e) {   
            e.printStackTrace();   
        }   
        return xmlStr;   
	}
	
	/**
	 * 
	 * Des:将XML字符串转化为一个指定类对象(只能是BaseXMLPojo的子类对象)<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-11
	 */
	public static BaseXMLPojo XMLToPojo(String xmlContent,Class clazz){
		try {
			BaseXMLPojo obj = (BaseXMLPojo)clazz.newInstance();
			
			Long rel = obj.toObject(xmlContent);
			if(rel==1L){
				return obj;
			}
			return null;
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}
	
	/**
	 * 
	 * Des:通过指定节点路径将XML字符串转化为一个指定类对象(只能是BaseXMLPojo的子类对象)<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-11
	 */
	public static BaseXMLPojo XMLToPojoByNodePath(String nodePath,String xmlContent,Class clazz){
		try {
			
			Document doc = getDocumentByData(xmlContent);
			XPathExpression expr = XPathUtil.getXPathExp(nodePath);
			NodeList ndl = (NodeList)expr.evaluate(doc,XPathConstants.NODESET);
			
			if(ndl!=null&&ndl.getLength()>0){
				Node nd = ndl.item(0);
				return XMLToPojo(getDomXml(nd),clazz);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}
	
	
	/**
	 * 
	 * Des:将XML字符串转化为一个指定类对象的集合(只能是BaseXMLPojo的子类对象)<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-11
	 */
	public static List XMLToPojoList(String xmlContent,Class clazz){
		try {
			List list = new ArrayList();
			BaseXMLPojo obj = (BaseXMLPojo)clazz.newInstance();
			String nodeName = obj.getNodeName();
			
			Document doc = getDocumentByData(xmlContent);
			NodeList ndl = doc.getElementsByTagName(nodeName);
			
			for(int i = 0;i < ndl.getLength();i++){
				String nodeXml = getDomXml(ndl.item(i));
				BaseXMLPojo obj2 = XMLToPojo(nodeXml,clazz);
				list.add(obj2);
			}
			return list;
		}catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}
	
	/**
	 * 
	 * Des:通过指定节点路径将XML字符串转化为一个指定类对象的集合(只能是BaseXMLPojo的子类对象)<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-13
	 */
	public static List XMLToPojoListByNodePath(String nodePath,String xmlContent,Class clazz){
		try {
			Document doc = getDocumentByData(xmlContent);
			XPathExpression expr = XPathUtil.getXPathExp(nodePath);
			NodeList ndl = (NodeList)expr.evaluate(doc,XPathConstants.NODESET);
			
			if(ndl!=null&&ndl.getLength()>0){
				Node nd = ndl.item(0);				
				return XMLToPojoList(getDomXml(nd),clazz);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} 
		return null;
	}
	
	/**
	 * 
	 * Des:用指定对象(只能是BaseXMLPojo的子类对象)的值来替换XML字符串中指定路径的节点,并返回替换后的XML字符串<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-13
	 */
	public static String replaceNode(String nodePath,String xmlContent,BaseXMLPojo baseXMLPojo){
		try{
			//先将给定的对象转换成节点对象
			Node node = baseXMLPojo.toNode();
			Document doc = getDocumentByData(xmlContent);
			XPathExpression expr = XPathUtil.getXPathExp(nodePath);
			NodeList ndl = (NodeList)expr.evaluate(doc,XPathConstants.NODESET);
			
			if(ndl!=null&&ndl.getLength()>0&&node!=null){
				Node nd = ndl.item(0);
				
				//比较指定路径的节点名是否和给定的对象的节点名属性值一致
				if(nd.getNodeName().equals(baseXMLPojo.getNodeName())){
					Node pnd = nd.getParentNode();
					Node tmpNode = doc.importNode(node,true);
					pnd.replaceChild(tmpNode,nd);
					
					return getDomXml(doc);
				}
			}
		}catch(Exception e){
			e.printStackTrace();
		}
		
		return null;
	}
	
	/**
	 * 
	 * Des:将一个对象(只能是BaseXMLPojo的子类对象)转化成XML各式字符串<br>
	 * Logic:<br>
	 * Alex crated the method at 2011-3-14
	 */
	public static String pojoToXML(BaseXMLPojo baseXMLPojo){
		try{
			return getDomXml(baseXMLPojo.toNode() );
		}catch(Exception e){
			e.printStackTrace();
		}
		
		return null;
	}
}
